package com.cskaoyan.javase._1extends._9override;

/**
 * 方法的重写/方法的覆盖(override)
 * 当父子类中出现同名成员方法时,再创建子类对象,调用该同名成员方法,结果是什么呢?
 * 结果体现出子类中方法的行为
 *
 * 那么我们还能不能去访问父类中方法行为呢?
 * 我们通过在父类中写一个同名方法的"Getter"方法,调用后发现仍然体现出子类的行为
 * 这种子类对象只能访问子类行为的现象,被称之为"方法的覆盖/重写"
 *
 * 那么这时父类中的同名方法去哪里了呢?
 * 方法在jvm内存中,不过是一段二进制的指令合集罢了,虽然创建子类对象,无法再直接去调用父类中同名方法了
 * 称之为"方法覆盖",但这个覆盖不是物理意义上的覆盖,而是由于"对象名.成员方法"访问机制的原因,体现出"方法的覆盖"
 * 这个父类中的同名方法,仍然可以使用"super."访问到.
 *
 * 接下来重点研究"对象名.成员方法"的访问和调用机制.
 * 日常开发中,"对象名.成员变量"是非常罕见的使用方式,绝大多数情况下,都是使用"对象名.成员方法"来实现操作.
 * 我们仍然从两个角度研究,"对象名.成员方法"的调用机制:
 *          1.访问范围
 *          2.调用结果
 * 同样的,创建对象,有三种方式:
 *          1.子类引用指向子类对象
 *          2.父类引用指向父类对象
 *          3.父类引用指向子类对象
 *
 * 首先"对象名.成员方法"的访问范围仍然是一个编译上的概念,和"对象名.成员变量"是一模一样的,都只需要看引用的数据类型即可.
 *
 * 重点来看"对象名.成员方法"的方法调用的结果
 *      重点看"父类引用指向子类对象"的调用结果
 *      这里调用父子类同名成员方法
 *          如果结果是子类的行为
 *              说明方法的调用结果要根据对象的类型来确定
 *          反之,如果结果是父类的行为
 *              说明方法的调用结果要根据引用的类型来确定
 *
 * 以上,总结,说明"对象名.成员方法"的调用结果,需要根据对象的具体类型来确定.
 * 如果对象是一个子类类型,不需要考虑引用是子类还是父类,统统体现出子类的行为
 * 如果对象是一个父类类型,那么肯定体现出父类的行为.(要想体现子类行为也不可能,因为访问不到)
 *
 *
 * 总结:
 * 综合对象名点访问成员方法的范围和结果，发现：
 *      1.访问范围仍然是要靠引用的数据类型来决定。
 *      2.但是方法的调用结果，就需要考虑对象的具体类型，是何种对象，就体现出它的行为。
 *
 * 注意事项：
 *      1.父子类中一旦存在父子类同名的成员方法，那么只要创建子类对象，
 *          在任何位置都无法再直接访问到父类成员方法了，这就是继承中的方法的覆盖。
 *      2.方法的调用之所以体现为覆盖，这是因为方法的调用结果是根据对象的实际类型决定的，和引用没有任何关系。
 *      3.当然，方法的覆盖不是物理意义上的覆盖，只是方法的访问机制决定的。
 *          这个父类中的同名方法，仍然可以使用super关键字去访问到，当然前提是有访问权限。
 *
 * @since 10:14
 * @author wuguidong@cskaoyan.onaliyun.com
 */
public class Demo {
    public static void main(String[] args) {
        Student s = new Student();
        s.eat();
        s.invokePersonEat();
        // s.superInvokePersonEat();

        /*Person p = new Person();
        p.eat();
        p.sleep();
        Student s = new Student();
        s.eat();
        s.playGame();
        s.sleep();*/
        // Person ps = new Student();
        // ps.eat();
        // ps.sleep();
        // ps.playGame();
        // ((Student) ps).playGame();
    }
}

class Person {
    public void eat() {
        System.out.println("人要吃饭,不然饿死了!");
    }

    public void sleep(){
        System.out.println("人都要睡觉!");
    }

    public void invokePersonEat() {
        eat();
    }
}

class Student extends Person {
    public void eat() {
        System.out.println("为了学习,废寝忘食!");
    }

    public void playGame(){
        System.out.println("学习时间,不玩游戏!学会了再玩!");
    }

    /*public void superInvokePersonEat() {
        super.eat();
    }*/
}